
package app;

import fuzzyLogic.*;

/**
 * Klasa zawierająca całą logikę sztucznej inteligencji sterującej autem.
 * Wraz z tworzeniem obiektu tej klasy tworzona jest logika.
 * Klasa ta umożliwia pobieranie wartości z logiki na podstawie danych wejściowych.
 * 
 * @author CygiDawid
 */
public class MyFuzzyLogic {
    private final FuzzyLogic _accLogic = new FuzzyLogic();
    private final FuzzyLogic _steerLogic = new FuzzyLogic();
    
    //<editor-fold defaultstate="collapsed" desc="LinguisticVariablesNames">
    private final static String STEER = "steer";
    private final static String ACCELERATION = "acceleration";
    private final static String ANGLE = "angle";
    private final static String ANGLE2 = "signedAngle";
    private final static String SPEED = "speed";
    //</editor-fold>
    
    
    public MyFuzzyLogic() {
        createAccelerationLogic();
        createSteerLogic();
    }
    
    /**
     * Utworzenie logiki rozmytej odpowiedzialnej za
     * sterowanie przyspieszeniem auta
     */
    private void createAccelerationLogic() {
        _accLogic.addVariable(createAccAngle());
        _accLogic.addVariable(createAccSpeed());
        _accLogic.addVariable(createAccAcceleration());
        
        _accLogic.setRulesFor2(new int[][] { {4, 4, 4, 4}, {4, 3, 2, 1}, {3, 3, 2, 1}, {3, 2, 0, 0}, {3, 2, 0, 0} });
    }
    
    /**
     * Utworzenie zmiennej lingwistycznej określającej kąt pomiędzy
     * autem, a następnym punktem (bez uwzględniania strony - prawa lub lewa)
     * @return Zmienna lingwistyczna określająca kąt
     */
    private LinguisticVariable createAccAngle() {
        LinguisticVariable result = new LinguisticVariable(ANGLE, 0, 180, 1);
        
        result.addSet(-1, 0, 5);
        result.addSet(3, 10, 15, 30);
        result.addSet(20, 40, 60);
        result.addSet(55, 70, 150, 180);
        result.addSet(150, 180, 181);
        
        return result;
    }
    
    /**
     * Utworzenie zmiennej lingwistycznej określającej prędkość auta
     * @return Zmienna lingwistyczna określająca prędkość
     */
    private LinguisticVariable createAccSpeed() {
        LinguisticVariable result = new LinguisticVariable(SPEED, -100, 100, 1);
        
        result.addSet(-101, -100, -33, 0);
        result.addSet(-33, 0, 33);
        result.addSet(0, 20, 33, 67);
        result.addSet(20, 67, 100);
        
        return result;
    }
    
    /**
     * Utworzenie zmiennej lingwistycznej określającej przyspieszenie auta
     * @return Zmienna lingwistyczna określająca przyspieszenie
     */
    private LinguisticVariable createAccAcceleration() {
        LinguisticVariable result = new LinguisticVariable(ACCELERATION, -100, 100, 1);
        
        result.addSet(-101, -100, -95);
        result.addSet(-100, -95, -33, 0);
        result.addSet(-5, 0, 5);
        result.addSet(5, 15, 30, 45);
        result.addSet(40, 75, 100);
        
        return result;
    }
    
    /**
     * Utworzenie logiki rozmytej odpowiedzialnej za sterowanie skrętem kół auta
     */
    private void createSteerLogic() {
        _steerLogic.addVariable(createSteerAngle());
        _steerLogic.addVariable(createSteerSteer());
        
        _steerLogic.setRulesFor1(new int[] { 0, 1, 2, 3 });
    }
    
    /**
     * Utworzenie zmiennej lingwistycznej określającej kąt pomiędzy
     * autem, a następnym punktem (bez uwzględniania strony)
     * @return Zmienna lingwistyczna określająca kąt
     */
    private LinguisticVariable createSteerAngle() {
        LinguisticVariable result = new LinguisticVariable(ANGLE2, 0, 180, 1);
        
        result.addSet(-1, 0, 5);
        result.addSet(4, 6, 8, 11);
        result.addSet(11, 13, 15, 17);
        result.addSet(15, 20, 180);
        
        return result;
    }
    
    /**
     * Utworzenie zmiennej lingwistycznej określającej moc skrętu koł auta
     * @return Zmienna lingwistyczna określająca moc skrętu
     */
    private LinguisticVariable createSteerSteer() {
        LinguisticVariable result = new LinguisticVariable(STEER, 0, 100, 1);
        
        result.addSet(-1, 0, 5);
        result.addSet(0, 15, 30, 40);
        result.addSet(15, 40, 50, 80);
        result.addSet(50, 100, 101);
        
        return result;
    }
    
    
    /**
     * Pobranie wartości mocy przyspieszenia odpowiadającej danym wejściowym
     * @param angle Kąt pomiędzy autem, a następnym punktem trasy
     * @param speed Prędkość auta
     * @return Moc skrętu
     */
    public double getAcceleration(double angle, double speed) {
        return _accLogic.getResult((int)angle, (int)speed);
    }
    
    /**
     * Pobranie wartości mocy skrętu odpowiadającej danym wejściowym
     * @param angle Kąt pomiędzy autem, a następnym punktem
     * @return Moc skrętu z uwzględnieniem strony
     */
    public double getSteer(double angle) {
        double sign = Math.signum(angle);
        double power = _steerLogic.getResult((int)Math.abs(angle));
        return power * sign;
    }
}
